using PhraseCorrector.Common;
using PhraseCorrector.SimplePinyin;
using PhraseCorrector.SpellCorrect;
using PhraseCorrector.SpellLook;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text.RegularExpressions;

namespace PhraseCorrector.DirectTanslate
{
    public class PinyinTranslator
    {

        #region 匹配使用的变量 
        // ///////////////////////////////////////////////////////////////////////////       
        /// <summary>
        /// 拼音词库
        /// </summary>
        public static Dictionary<string, string> PinyinDict = new Dictionary<string, string>();

        // ///////////////////////////////////////////////////////////////////////////////
        /// <summary>
        /// 最大容错单词个数
        /// </summary>
        private static int MaxLength { set; get; } = 0;

        #endregion

        #region 拼音库的创建与更新
        // ///////////////////////////////////////////////////////////////////////////////
        /// <summary>
        /// Pinyinlibrary 类的构造函数。
        /// </summary>
        /// <remarks>
        /// 当中英文对照字典（ChineseToEnglish.CElibrary）非空且拼音字典（PinyinDict）为空时，
        /// 自动创建拼音字典。这样做是为了确保在类实例化时，拼音字典已经准备好，
        /// 从而支持后续的相关操作。
        /// </remarks>
        public PinyinTranslator()
        {
            if (ChineseTraslator.CElibrary.Count > 0 && PinyinDict.Count == 0) 
                PinyinTranslator_Init();
        }

        // ///////////////////////////////////////////////////////////////////////////////
        /// <summary>
        /// 初始化拼音库
        /// </summary>
        public void PinyinTranslator_Init() {
            CreatePinyinDict();
            PinyinTranslator_InitSpell();
        }

        // ///////////////////////////////////////////////////////////////////////////////
        /// <summary>
        /// 初始化拼音纠错库
        /// </summary>
        public void PinyinTranslator_InitSpell() {
            new PinyinSpell();
            MaxLength = (int)(PinyinSpell.SpellHandle.MaxLength * 0.5);
        }

        #endregion

        #region 生成词树

        // ///////////////////////////////////////////////////////////////////////////////
        /// <summary>
        /// 创建拼音字典，将汉字转换为拼音并尝试添加到字典中
        /// </summary>
        private void CreatePinyinDict()
        {
            // 遍历中文及其对应的英文图书馆，将每个中文字符转换为拼音并添加到字典中
            foreach (var item in ChineseTraslator.CElibrary)
                TryAdd(Pinyin.GetPinyin(item.Key), item.Key);
        }

        // ///////////////////////////////////////////////////////////////////////////////
        /// <summary>
        /// 尝试向拼音字典中添加一个新的键值对
        /// </summary>
        /// <param name="pinyin">拼音</param>
        /// <param name="chinese">对应的汉字</param>
        public void TryAdd(string pinyin, string chinese)
        {
            // 如果拼音或汉字为空，则不进行添加操作
            if (string.IsNullOrEmpty(pinyin) || string.IsNullOrEmpty(chinese)) return;
            // 调用Add方法实际添加键值对
            Add(pinyin, chinese);
        }

        // ///////////////////////////////////////////////////////////////////////////////
        /// <summary>
        /// 向拼音字典中添加一个新的键值对
        /// </summary>
        /// <param name="pinyin">拼音</param>
        /// <param name="chinese">对应的汉字</param>
        public void Add(string pinyin, string chinese)
        {
            // 如果拼音或汉字为空，则不进行添加操作
            if (!PinyinDict.TryAdd(pinyin, chinese))
                // 如果拼音已存在但值为空，则更新为新的汉字
                if (PinyinDict[pinyin] == "") PinyinDict[pinyin] = chinese;
        }

        #endregion

        #region 拼音速查

        // ///////////////////////////////////////////////////////////////////////////////
        /// <summary>
        /// 根据给定的内容查找所有匹配的结果
        /// </summary>
        /// <param name="content">要查找的内容</param>
        /// <returns>返回一个包含所有查找结果的列表</returns>
        public static List<PhraseResult> TreeSearch(string content)
        {
            // 初始化结果列表
            var instance = new PinyinTranslator();
            // 使用拼音字典和自定义正则表达式数组，转换查找内容
            // 调用内部方法FindAllResult来处理查找结果
            return instance.FindAllResult(content, new FastTree(PinyinDict).TransformCustomizedWords(instance.RegexSuggestArray(content)));
        }

        // ///////////////////////////////////////////////////////////////////////////////
        /// <summary>
        /// 将中文标点符号后的空格规范化
        /// </summary>
        /// <param name="content">输入的字符串内容</param>
        /// <returns>规范化后的字符串数组</returns>
        public string[] RegexSuggestArray(string content)
        {
            // 使用正则表达式替换中文标点符号后的空格
            return Utilities.ReplaceBdfh(content, " $1").Split(' ');
        }

        // ///////////////////////////////////////////////////////////////////////////////
        /// <summary>
        /// 创建一个包含搜索结果的列表
        /// </summary>
        /// <param name="content">搜索内容的英文版本</param>
        /// <param name="result">搜索内容的中文版本</param>
        /// <returns>包含一个ECResult对象的列表</returns>
        public List<PhraseResult> FindAllResult(string content, string result)
        {
            // 初始化一个包含单个ECResult对象的列表
            return new List<PhraseResult>(){
                new PhraseResult() {
                    Chinese=  result,
                    Words=content
                }
            };
        }

        #endregion

        #region 纠错

        // //////////////////////////////////////////////////////////////////////////
        /// <summary>
        /// 拼写纠正方法，用于修正输入的术语。
        /// </summary>
        /// <remarks>
        /// 多单术语成的术语纠错时与字典定义描述方法相同，使用'_'分割
        /// </remarks>
        /// <param name="Phrase">需要进行拼写纠正的术语。</param>
        /// <returns>返回纠正后的术语结果。</returns>
        public static PhraseResult SpellPhraseCorrect(string Phrase) {
            // 计算术语的拼写纠正建议
            var suggestions = SpellPhraseCorrectCal(Phrase);
            // 如果有建议，则处理第一个建议，否则返回原始术语及默认值
            return (suggestions.Count() > 0)
                ? SpellPhraseCorrectResult(suggestions.First())
                : SpellPhraseCorrectEmptyResult(Phrase);
        }

        // //////////////////////////////////////////////////////////////////////////
        /// <summary>
        /// 计算术语的拼写纠正建议的辅助方法。
        /// </summary>
        /// <param name="Phrase">需要计算的术语。</param>
        /// <returns>返回按相关性排序的建议列表。</returns>
        private static IOrderedEnumerable<SuggestItem> SpellPhraseCorrectCal(string Phrase) {
            // 返回按核心值降序排序的建议列表
            // 使用Lookup方法,最大错误字符数 <= 11
            return PinyinSpell.SpellHandle.Lookup(Phrase, Verbosity.Similarity, MaxLength).OrderByDescending(x => x.score).ThenByDescending(x => x.count);
        }

        // //////////////////////////////////////////////////////////////////////////
        /// <summary>
        /// 根据建议项生成拼写纠正结果。
        /// </summary>
        /// <param name="input">包含纠正建议的建议项。</param>
        /// <returns>返回包含纠正结果的 ECResult 对象。</returns>
        private static PhraseResult SpellPhraseCorrectResult(SuggestItem input) {
            var chinese = TreeSearch(input.term);
            // 使用建议项中的数据生成纠正结果
            return new PhraseResult() {
                Words = input.term,
                Chinese = chinese.Count > 0 ? chinese[0].Chinese : "",
                Distance = input.distance,
                Score = input.score,
            };
        }

        // //////////////////////////////////////////////////////////////////////////
        /// <summary>
        /// 生成拼写纠正空结果。
        /// </summary>
        /// <remarks>
        /// 多单术语成的特定术语返回时需将字典定义描述方法'_'分割更改为' '空格分割
        /// </remarks>
        /// <param name="input">输入的文本，当没有纠正建议时返回。</param>
        /// <returns>返回包含原始文本和默认值的 ECResult 对象。</returns>
        public static PhraseResult SpellPhraseCorrectEmptyResult(string input) {
            // 生成并返回没有纠正建议时的结果
            return new PhraseResult() {
                Words = input,
                Distance = 0,
                Score = 0,
            };
        }
        #endregion
    }
}

